package com.kwdb.sdk;

import com.kwdb.sdk.data.DataPoint;
import com.kwdb.sdk.exception.KWDBException;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;

/**
 * 测试数据集下载器
 * 从各种开源数据集下载真实测试数据
 */
public class TestDatasetDownloader {
    
    private static final String DATA_DIR = "test-data";
    
    /**
     * 下载InfluxDB NOAA水数据库数据集
     * @return 数据集文件路径
     * @throws IOException 下载异常
     */
    public String downloadNOAADataset() throws IOException {
        System.out.println("正在下载NOAA水数据库数据集...");
        
        String url = "https://s3.amazonaws.com/noaa.water-database/NOAA_data.txt";
        String filename = "NOAA_data.txt";
        
        return downloadFile(url, filename);
    }
    
    /**
     * 下载TimescaleDB NYC出租车数据集
     * @return 数据集文件路径
     * @throws IOException 下载异常
     */
    public String downloadNYCTaxiDataset() throws IOException {
        System.out.println("正在下载NYC出租车数据集...");
        
        String url = "https://timescaledata.blob.core.windows.net/datasets/nyc_data.tar.gz";
        String filename = "nyc_data.tar.gz";
        
        return downloadFile(url, filename);
    }
    
    /**
     * 下载InfluxDB示例数据集
     * @return 数据集文件路径
     * @throws IOException 下载异常
     */
    public String downloadInfluxDBDataset() throws IOException {
        System.out.println("正在下载InfluxDB示例数据集...");
        
        String url = "https://s3.amazonaws.com/noaa.water-database/NOAA_data.txt";
        String filename = "influxdb_sample.txt";
        
        return downloadFile(url, filename);
    }
    
    /**
     * 下载IoT传感器模拟数据集
     * @return 数据集文件路径
     * @throws IOException 下载异常
     */
    public String downloadIoTSensorDataset() throws IOException {
        System.out.println("正在下载IoT传感器数据集...");
        
        // 使用一个公开的IoT数据集
        String url = "https://archive.ics.uci.edu/ml/machine-learning-databases/00235/household_power_consumption.zip";
        String filename = "household_power_consumption.zip";
        
        return downloadFile(url, filename);
    }
    
    /**
     * 下载股票价格数据集
     * @return 数据集文件路径
     * @throws IOException 下载异常
     */
    public String downloadStockPriceDataset() throws IOException {
        System.out.println("正在下载股票价格数据集...");
        
        // 使用Yahoo Finance的公开数据
        String url = "https://query1.finance.yahoo.com/v7/finance/download/AAPL?period1=1262304000&period2=1609459200&interval=1d&events=history";
        String filename = "AAPL_stock_data.csv";
        
        return downloadFile(url, filename);
    }
    
    /**
     * 下载网络监控数据集
     * @return 数据集文件路径
     * @throws IOException 下载异常
     */
    public String downloadNetworkMonitoringDataset() throws IOException {
        System.out.println("正在下载网络监控数据集...");
        
        // 使用KDD Cup 1999数据集
        String url = "https://kdd.ics.uci.edu/databases/kddcup99/kddcup.data.gz";
        String filename = "kddcup99_network_data.gz";
        
        return downloadFile(url, filename);
    }
    
    /**
     * 下载系统监控数据集
     * @return 数据集文件路径
     * @throws IOException 下载异常
     */
    public String downloadSystemMonitoringDataset() throws IOException {
        System.out.println("正在下载系统监控数据集...");
        
        // 使用Google Cluster Trace数据集
        String url = "https://github.com/google/cluster-data/archive/master.zip";
        String filename = "google_cluster_trace.zip";
        
        return downloadFile(url, filename);
    }
    
    /**
     * 通用文件下载方法
     * @param urlString 下载URL
     * @param filename 文件名
     * @return 下载文件路径
     * @throws IOException 下载异常
     */
    private String downloadFile(String urlString, String filename) throws IOException {
        // 创建数据目录
        Files.createDirectories(Paths.get(DATA_DIR));
        
        String filepath = DATA_DIR + File.separator + filename;
        File file = new File(filepath);
        
        // 如果文件已存在，直接返回
        if (file.exists()) {
            System.out.println("文件已存在: " + filepath);
            return filepath;
        }
        
        URL url = new URL(urlString);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setConnectTimeout(30000);
        connection.setReadTimeout(60000);
        
        // 设置User-Agent避免被拒绝
        connection.setRequestProperty("User-Agent", "KWDB-SDK-Test/1.0");
        
        int responseCode = connection.getResponseCode();
        if (responseCode != HttpURLConnection.HTTP_OK) {
            throw new IOException("下载失败，HTTP状态码: " + responseCode);
        }
        
        long contentLength = connection.getContentLengthLong();
        System.out.println("文件大小: " + (contentLength > 0 ? contentLength + " bytes" : "未知"));
        
        try (InputStream inputStream = connection.getInputStream();
             FileOutputStream outputStream = new FileOutputStream(file)) {
            
            byte[] buffer = new byte[8192];
            int bytesRead;
            long totalBytesRead = 0;
            
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
                totalBytesRead += bytesRead;
                
                if (contentLength > 0) {
                    double progress = (double) totalBytesRead / contentLength * 100;
                    if (totalBytesRead % (1024 * 1024) == 0) { // 每MB显示一次进度
                        System.out.printf("下载进度: %.1f%%\r", progress);
                    }
                }
            }
            
            System.out.println("\n下载完成: " + filepath);
        }
        
        return filepath;
    }
    
    /**
     * 解析NOAA数据集为DataPoint列表
     * @param filepath 文件路径
     * @param maxLines 最大行数（0表示全部）
     * @return DataPoint列表
     * @throws IOException 解析异常
     */
    public List<DataPoint> parseNOAADataset(String filepath, int maxLines) throws IOException {
        System.out.println("正在解析NOAA数据集...");
        
        List<DataPoint> dataPoints = new ArrayList<>();
        int lineCount = 0;
        
        try (BufferedReader reader = new BufferedReader(new FileReader(filepath))) {
            String line;
            while ((line = reader.readLine()) != null && (maxLines == 0 || lineCount < maxLines)) {
                if (line.trim().isEmpty() || line.startsWith("#")) {
                    continue;
                }
                
                try {
                    DataPoint dataPoint = parseNOAALine(line);
                    if (dataPoint != null) {
                        dataPoints.add(dataPoint);
                    }
                } catch (Exception e) {
                    System.err.println("解析行失败: " + line + ", 错误: " + e.getMessage());
                }
                
                lineCount++;
                if (lineCount % 10000 == 0) {
                    System.out.println("已解析: " + lineCount + " 行");
                }
            }
        }
        
        System.out.println("NOAA数据集解析完成，共 " + dataPoints.size() + " 个数据点");
        return dataPoints;
    }
    
    /**
     * 解析NOAA数据行
     * @param line 数据行
     * @return DataPoint
     */
    private DataPoint parseNOAALine(String line) {
        // NOAA数据格式: measurement,tag1=value1,tag2=value2 field1=value1,field2=value2 timestamp
        String[] parts = line.split(" ");
        if (parts.length < 2) {
            return null;
        }
        
        String measurementAndTags = parts[0];
        String fields = parts[1];
        String timestamp = parts.length > 2 ? parts[2] : String.valueOf(System.currentTimeMillis());
        
        // 解析measurement和tags
        String[] measurementParts = measurementAndTags.split(",");
        String measurement = measurementParts[0];
        
        DataPoint dataPoint = new DataPoint(measurement);
        
        // 添加tags
        for (int i = 1; i < measurementParts.length; i++) {
            String[] tagParts = measurementParts[i].split("=");
            if (tagParts.length == 2) {
                dataPoint.addTag(tagParts[0], tagParts[1]);
            }
        }
        
        // 添加fields
        String[] fieldParts = fields.split(",");
        for (String fieldPart : fieldParts) {
            String[] fieldKeyValue = fieldPart.split("=");
            if (fieldKeyValue.length == 2) {
                String key = fieldKeyValue[0];
                String value = fieldKeyValue[1];
                
                // 尝试解析为数字
                try {
                    if (value.contains(".")) {
                        dataPoint.addField(key, Double.parseDouble(value));
                    } else {
                        dataPoint.addField(key, Long.parseLong(value));
                    }
                } catch (NumberFormatException e) {
                    dataPoint.addField(key, value);
                }
            }
        }
        
        // 设置时间戳
        try {
            dataPoint.setTimestamp(Long.parseLong(timestamp));
        } catch (NumberFormatException e) {
            dataPoint.setTimestamp(System.currentTimeMillis());
        }
        
        return dataPoint;
    }
    
    /**
     * 解析CSV格式数据集
     * @param filepath 文件路径
     * @param maxLines 最大行数
     * @return DataPoint列表
     * @throws IOException 解析异常
     */
    public List<DataPoint> parseCSVDataset(String filepath, int maxLines) throws IOException {
        System.out.println("正在解析CSV数据集...");
        
        List<DataPoint> dataPoints = new ArrayList<>();
        int lineCount = 0;
        
        try (BufferedReader reader = new BufferedReader(new FileReader(filepath))) {
            String headerLine = reader.readLine();
            if (headerLine == null) {
                return dataPoints;
            }
            
            String[] headers = headerLine.split(",");
            String line;
            
            while ((line = reader.readLine()) != null && (maxLines == 0 || lineCount < maxLines)) {
                String[] values = line.split(",");
                if (values.length != headers.length) {
                    continue;
                }
                
                DataPoint dataPoint = new DataPoint("csv_data");
                
                for (int i = 0; i < headers.length; i++) {
                    String header = headers[i].trim();
                    String value = values[i].trim();
                    
                    if (header.equals("timestamp") || header.equals("time")) {
                        try {
                            dataPoint.setTimestamp(Long.parseLong(value));
                        } catch (NumberFormatException e) {
                            dataPoint.setTimestamp(System.currentTimeMillis());
                        }
                    } else {
                        // 尝试解析为数字
                        try {
                            if (value.contains(".")) {
                                dataPoint.addField(header, Double.parseDouble(value));
                            } else {
                                dataPoint.addField(header, Long.parseLong(value));
                            }
                        } catch (NumberFormatException e) {
                            dataPoint.addField(header, value);
                        }
                    }
                }
                
                dataPoints.add(dataPoint);
                lineCount++;
                
                if (lineCount % 1000 == 0) {
                    System.out.println("已解析: " + lineCount + " 行");
                }
            }
        }
        
        System.out.println("CSV数据集解析完成，共 " + dataPoints.size() + " 个数据点");
        return dataPoints;
    }
    
    /**
     * 解压GZ文件
     * @param gzFilePath GZ文件路径
     * @return 解压后的文件路径
     * @throws IOException 解压异常
     */
    public String extractGZFile(String gzFilePath) throws IOException {
        String outputPath = gzFilePath.substring(0, gzFilePath.lastIndexOf('.'));
        
        try (GZIPInputStream gzInputStream = new GZIPInputStream(new FileInputStream(gzFilePath));
             FileOutputStream outputStream = new FileOutputStream(outputPath)) {
            
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = gzInputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }
        
        System.out.println("GZ文件解压完成: " + outputPath);
        return outputPath;
    }
    
    /**
     * 清理测试数据目录
     */
    public void cleanup() {
        try {
            Files.walk(Paths.get(DATA_DIR))
                    .sorted((a, b) -> b.compareTo(a)) // 反向排序，先删除文件再删除目录
                    .forEach(path -> {
                        try {
                            Files.delete(path);
                        } catch (IOException e) {
                            System.err.println("删除文件失败: " + path + ", 错误: " + e.getMessage());
                        }
                    });
            System.out.println("测试数据目录清理完成");
        } catch (IOException e) {
            System.err.println("清理目录失败: " + e.getMessage());
        }
    }
}
